package com.gking.aiService.realm;


import com.gking.aiService.common.Result;
import com.gking.aiService.serviceUtils.RemoteInteraction.RemoteInteractionService;
import com.gking.aiService.utils.GetAuthInfoUtil;
import com.gking.aiService.utils.commonUtil.RandomGenerator;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static com.gking.aiService.common.RedisConstants.*;


@Slf4j
public class CustomAuthFilter extends AuthenticatingFilter {

    private final RemoteInteractionService remoteInteractionService;

    private final StringRedisTemplate stringRedisTemplate;

    public CustomAuthFilter(StringRedisTemplate stringRedisTemplate, RemoteInteractionService remoteInteractionService) {
        this.stringRedisTemplate = stringRedisTemplate;
        this.remoteInteractionService = remoteInteractionService;
    }


    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest req = (HttpServletRequest) request;
        GetAuthInfoUtil getAuthInfoUtil = new GetAuthInfoUtil(stringRedisTemplate, req);

        String tokenUserKey = getAuthInfoUtil.getTokenUserKey();
        String userId = getAuthInfoUtil.getUserServerInfo();
        String userLoginIp = getAuthInfoUtil.getUserLoginIp();
        String userDeviceInfo = getAuthInfoUtil.getUserDeviceInfo();

        String url = req.getRequestURI();
        String ipAddress = GetAuthInfoUtil.getClientIp(req);
        String equipment = GetAuthInfoUtil.getClientDeviceInfo(req);

        String pwd = stringRedisTemplate.opsForValue().get(Login_User_Auth + tokenUserKey);
        if (pwd == null) {
            pwd = RandomGenerator.generateRandomString(12);
            stringRedisTemplate.opsForValue().set(
                    Login_User_Auth + tokenUserKey, pwd,
                    10L, TimeUnit.SECONDS);
        } else {
            stringRedisTemplate.opsForValue().set(
                    Login_User_Auth + tokenUserKey, pwd,
                    10L, TimeUnit.SECONDS);
        }

        if (userId == null || userLoginIp == null || userDeviceInfo == null) {
            log.info("用户未存有登录凭证，跳转去往主系统中验证");
            Result<Map> userLoginAuth = remoteInteractionService.getUserLoginAuth(req);
            log.info("主系统 userLoginAuth : {} ", userLoginAuth);
            if (userLoginAuth.getData() == null) return null;

            Map<String, String> data = userLoginAuth.getData();

            getAuthInfoUtil.setUserServerInfo(tokenUserKey, data.get("userId"));
            getAuthInfoUtil.setUserLoginIp(tokenUserKey, data.get("ip"));
            getAuthInfoUtil.setUserDeviceInfo(tokenUserKey, data.get("device"));
            return new CustomAuthToken(tokenUserKey, pwd);
        }

        if (!Objects.equals(equipment, userDeviceInfo)) {
            log.info("用户登录设备不匹配");
            return null;
        }

        if (!Objects.equals(ipAddress, userLoginIp)) {
            log.info("用户登录IP不匹配");
            return null;
        }

        return new CustomAuthToken(tokenUserKey, pwd);
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        AuthenticationToken token = createToken(request, response);

        if (token == null) {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access token is missing");
            return false;
        }

        try {
            Subject subject = getSubject(request, response);
            subject.login(token);
            log.info("CustomAuthFilter 用户授权登录成功");
            return true;
        } catch (AuthenticationException e) {
            log.info("AuthenticationException : {}", e.getMessage());
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid access token");
            return false;
        }
    }

    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
        log.info("onLoginSuccess");
        return true;
    }

    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        try {
            log.info("onLoginFailure : {}", e.getMessage());
            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
        return false;
    }
}
